/*
 *------------------------------------------------------------------------------
 * @File      :    gc2053_mipi.c
 * @Date      :    2022-3-10
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 2053
#define SNS_NAME  "gc2053_mipi"
#define DEV_TYPE MCSI

/****************************************************************************
 * global variables                                                            *
 ****************************************************************************/
static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];
static VISS_DEV gaVissDev[ISP_MAX_DEV_NUM] = {-1};

/*
 * 2lane YUV init
 */
static const SNS_REG_S s_aInitRegList[] = {
    /* window_size=1928*1080,mipi 2lane, */
    /* mclk=24mhz, mipi_clock=300mhz, frame_rate=30fps,
     * row_time=29.33us pclk =74.25M
     */
    /* pixel_line_total=2200,line_frame_total=1125 */
    /* system */
    {0xfe, 0x80},
    {0xfe, 0x80},
    {0xfe, 0x80},
    {0xfe, 0x00},
    {0xf2, 0x00}, /* [1]I2C_open_ena [0]pwd_dn */
    {0xf3, 0x00}, /* 0f//00[3]Sdata_pad_io [2:0]Ssync_pad_io */
    {0xf4, 0x36}, /* [6:4]pll_ldo_set */
     /* [7]soc_mclk_enable [6]pll_ldo_en
      * [5:4]cp_clk_sel [3:0]cp_clk_div
      */
    {0xf5, 0xc0},
    {0xf6, 0x44}, /* [7:3]wpllclk_div [2:0]refmp_div */
    /* [7]refdiv2d5_en [6]refdiv1d5_en [5:4]scaler_mode
     * [3]refmp_enb [1]div2en [0]pllmp_en
     */
    {0xf7, 0x01},
    {0xf8, 0x32}, /* 38////38//[7:0]pllmp_div */
    /* 82//[7:3]rpllclk_div [2:1]pllmp_prediv [0]analog_pwc */
    {0xf9, 0x42},
    {0xfc, 0x8e},
    /*cisctl&analog*/
    {0xfe, 0x00},
    {0x87, 0x18}, /* [6]aec_delay_mode */
    {0xee, 0x30}, /* [5:4]dwen_sramen */
    {0xd0, 0xb7}, /* ramp_en */
    {0x03, 0x04},
    {0x04, 0x10},
    {0x05, 0x04}, /* 05 */
    {0x06, 0x4c}, /* 28//[11:0]hb */
    {0x07, 0x00},
    {0x08, 0xfa},
    {0x09, 0x00},
    {0x0a, 0x02}, /* cisctl row start */
    {0x0b, 0x00},
    {0x0c, 0x02}, /* cisctl col start */
    {0x0d, 0x04},
    {0x0e, 0x40},
    {0x0f, 0x07},
    {0x10, 0x88},
    {0x12, 0xe2}, /* vsync_ahead_mode */
    {0x13, 0x16},
    {0x19, 0x0a}, /* ad_pipe_num */
    {0x21, 0x1c}, /* eqc1fc_eqc2fc_sw */
    {0x28, 0x0a}, /* 16//eqc2_c2clpen_sw */
    {0x29, 0x24}, /* eq_post_width */
    {0x2b, 0x04}, /* c2clpen --eqc2 */
    {0x32, 0xf8}, /* [5]txh_en ->avdd28 */
    {0x37, 0x03}, /* [3:2]eqc2sel=0 */
    {0x39, 0x15}, /* 17 //[3:0]rsgl */
    {0x43, 0x07}, /* vclamp */
    {0x44, 0x40}, /* 0e//post_tx_width */
    {0x46, 0x0b}, /* txh?a?a3.2v */
    {0x4b, 0x20}, /* rst_tx_width */
    {0x4e, 0x08}, /* 12//ramp_t1_width */
    {0x55, 0x20}, /* read_tx_width_pp */
    {0x66, 0x05}, /* 18//stspd_width_r1 */
    {0x67, 0x05}, /* 40//5//stspd_width_r */
    {0x77, 0x01}, /* dacin offset x31 */
    {0x78, 0x00}, /* dacin offset */
    {0x7c, 0x93}, /* [1:0] co1comp */
    {0x8c, 0x12}, /* 12 ramp_t1_ref */
    {0x8d, 0x92},
    {0x90, 0x00},
    {0x41, 0x04},
    {0x42, 0x65},
    {0x9d, 0x10},
    {0xce, 0x7c}, /* 70//78//[4:2]c1isel */
    {0xd2, 0x41}, /* [5:3]c2clamp */
    {0xd3, 0xdc}, /* 0x39[7]=0,0xd3[3]=1 rsgh=vref */
    {0xe6, 0x40}, /* ramps offset */
    /*gain*/
    {0xb6, 0xc0},
    {0xb0, 0x70},
    {0xb1, 0x01},
    {0xb2, 0x00},
    {0xb3, 0x00},
    {0xb4, 0x00},
    {0xb8, 0x01},
    {0xb9, 0x00},
    /*blk*/
    {0x26, 0x30},
    {0xfe, 0x01},
    {0x40, 0x23},
    {0x55, 0x07},
    {0x60, 0x00}, /* [7:0]WB_offset */
    {0xfe, 0x04},
    {0x14, 0x78},
    {0x15, 0x78},
    {0x16, 0x78},
    {0x17, 0x78},
    /*window*/
    {0xfe, 0x01},
    {0x94, 0x01},
    {0x95, 0x04},
    {0x96, 0x38}, /* [10:0]out_height */
    {0x97, 0x07},
    {0x98, 0x80}, /* [11:0]out_width */
    /*ISP*/
    {0xfe, 0x01},
    {0x01, 0x05},
    {0x02, 0x89},
    {0x04, 0x01},
    {0x07, 0xa6},
    {0x08, 0xa9},
    {0x09, 0xa8},
    {0x0a, 0xa7},
    {0x0b, 0xff},
    {0x0c, 0xff},
    {0x0f, 0x00},
    {0x50, 0x1c},
    {0x89, 0x03},
    {0xfe, 0x04},
    {0x28, 0x86},
    {0x29, 0x86},
    {0x2a, 0x86},
    {0x2b, 0x68},
    {0x2c, 0x68},
    {0x2d, 0x68},
    {0x2e, 0x68},
    {0x2f, 0x68},
    {0x30, 0x4f},
    {0x31, 0x68},
    {0x32, 0x67},
    {0x33, 0x66},
    {0x34, 0x66},
    {0x35, 0x66},
    {0x36, 0x66},
    {0x37, 0x66},
    {0x38, 0x62},
    {0x39, 0x62},
    {0x3a, 0x62},
    {0x3b, 0x62},
    {0x3c, 0x62},
    {0x3d, 0x62},
    {0x3e, 0x62},
    {0x3f, 0x62},

    /*DVP & MIPI*/
    {0xfe, 0x01},
    /*
     * [5]OUT_gate_mode [4]hsync_delay_half_pclk [3]data_delay_half_pclk
     * [2]vsync_polarity [1]hsync_polarity [0]pclk_out_polarity
     */
    {0x9a, 0x06},
    {0xfe, 0x00},
     /* [7:6]updn [5:4]drv_high_data [3:2]drv_low_data [1:0]drv_pclk */
    {0x7b, 0x2a},
    {0x23, 0x2d}, /* [3]rst_rc [2:1]drv_sync [0]pwd_rc */
    {0xfe, 0x03},
     /* 20//27[6:5]clkctr [2]phy-lane1_en [1]phy-lane0_en [0]phy_clk_en */
    {0x01, 0x27},
    /* [7:6]data1ctr [5:4]data0ctr [3:0]mipi_diff */
    {0x02, 0x56},
     /* b2//b6[7]clklane_p2s_sel [6:5]data0hs_ph
      * [4]data0_delay1s [3]clkdelay1s [2]mipi_en [1:0]clkhs_ph
      */
    {0x03, 0x8e},
    {0x12, 0x80},
    {0x13, 0x07}, /* LWC */
    {0x15, 0x12}, /* [1:0]clk_lane_mode */
    {0xfe, 0x00},
    /* 40//91[7]lane_ena [6]DVPBUF_ena [5]ULPEna [4]MIPI_ena [3] */
    {0x3e, 0x91},
};


static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 20},
    {SNS_RESET,  SNS_UP},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_UP},
    {SNS_DELAY, 20},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
};

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = GC2053_MIPI_1920_1080_30FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .stSize                     = {1920, 1080},
        .u32ModuleClk               = 148500000,
        .u32Mclock                  = 24000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 148000000,
        .u32IppuClk                 = 297000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 1125,
        .u32Hts                     = 2200,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aInitRegList,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aInitRegList),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 445*1000*1000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    }

};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 8;
    pstSnsState->stI2cInfo.u8ValBits = 8;
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x37;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{

    EI_U8 u8Tmp[2];
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 u16Id;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);
    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0xF0, &u8Tmp[0]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x\n", u8Tmp[0]);
        return EI_FAILURE;
    }
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0xF1, &u8Tmp[1]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x,tmp[1]=%x\n", u8Tmp[0], u8Tmp[1]);
        return EI_FAILURE;
    }
    u16Id = (u8Tmp[0] << 8) | u8Tmp[1];
    PRT_VISS_INFO("id: 0x%04x.\n", u16Id);
    if (u16Id != 0x2053) {
        PRT_VISS_ERR("ID wrong! (0x%04x != 0x2053)\n", u16Id);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    PRT_VISS_INFO("%s dev : %d CAMERA_Stream*******%d\n", SNS_NAME, dev, bOn);
    return EI_SUCCESS;
}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err\n", SNS_NAME);
            return s32Ret;
        }
    }

    PRT_VISS_INFO("%s writeRegList success\n", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return ;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFrameRate(VISS_DEV VissDev, EI_FLOAT f32Fps)
{
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;

    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;
    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x41, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x42, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x41, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x42, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_SetFrameRate error\n");
            return s32Ret;
        }
    } else {
        return EN_ERR_NOT_SUPPORT;
    }

    pstSnsState->pstSnsAttr->u32Vts = u32Vts;

    return EI_SUCCESS;

}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;
    pstSensorExpFunc->pfnSensorSetFrameRate   = CAMERA_SetFrameRate;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAeDefault(ISP_DEV dev, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{

    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFps(ISP_DEV dev, EI_FLOAT f32Fps, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return CAMERA_SetFrameRate(Dev, f32Fps);
}

static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts, u32Vmax;
    EI_U32 shutter_time;
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    CAMERA_CHECK_POINTER(afIntTime);
    pstSnsState->afIntTime[0] = afIntTime[0];
    pstSnsState->afIntTime[1] = afIntTime[1];
    pstSnsState->afIntTime[2] = afIntTime[2];
    pstSnsState->afIntTime[3] = afIntTime[3];
    pstSnsState->IspDev = dev;
    CAMERA_CHECK_POWERON(pstSnsState);

    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;
    u32Vts = pstSnsState->pstSnsAttr->u32Vts;
    if ((u32Pclk == 0) || (u32Hts == 0) || (u32Vts == 0)) {
        PRT_VISS_ERR("error! u32Pclk %d, u32Hts %d, u32Vts %d\n", u32Pclk, u32Hts, u32Vts);
        return EI_FAILURE;
    }

    /* afIntTime[0] long/medium/short/vshort exptime (s) */
    shutter_time = afIntTime[0] * u32Pclk / u32Hts;

    //printf("exp_time: %d, %f(s)!\n", shutter_time, afIntTime[0]);
    if (shutter_time < 1) {
        shutter_time = 1;
    }

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (shutter_time > u32Vts) {
            u32Vmax = shutter_time;
        } else {
            u32Vmax = u32Vts;
        }

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xfe, 0x00);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x41, u32Vmax >> 8);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x42, u32Vmax);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x03, (shutter_time >> 8) & 0x3f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x04, (shutter_time) & 0xff);

        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("\n");
        }

    }

    afIntTime[0] = (EI_FLOAT)(shutter_time) * u32Hts / u32Pclk;

    return s32Ret;
}


static EI_U32 LinerRegValTable[29][4] = {
    {0x00, 0x00, 0x01, 0x00},
    {0x00, 0x10, 0x01, 0x0c},
    {0x00, 0x20, 0x01, 0x1b},
    {0x00, 0x30, 0x01, 0x2c},
    {0x00, 0x40, 0x01, 0x3f},
    {0x00, 0x50, 0x02, 0x16},
    {0x00, 0x60, 0x02, 0x35},
    {0x00, 0x70, 0x03, 0x16},
    {0x00, 0x80, 0x04, 0x02},
    {0x00, 0x90, 0x04, 0x31},
    {0x00, 0xa0, 0x05, 0x32},
    {0x00, 0xb0, 0x06, 0x35},
    {0x00, 0xc0, 0x08, 0x04},
    {0x00, 0x5a, 0x09, 0x19},
    {0x00, 0x83, 0x0b, 0x0f},
    {0x00, 0x93, 0x0d, 0x12},
    {0x00, 0x84, 0x10, 0x00},
    {0x00, 0x94, 0x12, 0x3a},
    {0x01, 0x2c, 0x1a, 0x02},
    {0x01, 0x3c, 0x1b, 0x20},
    {0x00, 0x8c, 0x20, 0x0f},
    {0x00, 0x9c, 0x26, 0x07},
    {0x02, 0x64, 0x36, 0x21},
    {0x02, 0x74, 0x37, 0x3a},
    {0x00, 0xc6, 0x3d, 0x02},
    {0x00, 0xdc, 0x3f, 0x3f},
    {0x02, 0x85, 0x3f, 0x3f},
    {0x02, 0x95, 0x3f, 0x3f},
    {0x00, 0xce, 0x3f, 0x3f},
};

static EI_U32 analog_gain_table[29] = {
    1024,
    1184,
    1424,
    1632,
    2032,
    2352,
    2832,
    3248,
    4160,
    4800,
    5776,
    6640,
    8064,
    9296,
    11552,
    13312,
    16432,
    18912,
    22528,
    25936,
    31840,
    36656,
    45600,
    52512,
    64768,
    82880,
    88000,
    107904,
    113168,
};

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U8 total;
    EI_U8 i = 0;
    EI_U32 tol_dig_gain = 0, dgain = 0;
    EI_U32 Gain = 0;

    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    pstSnsState->fGain = fGain;
    CAMERA_CHECK_POWERON(pstSnsState);

    if (fGain < 1)
        fGain = 1;
    if (fGain > 127)
        fGain = 127;

    Gain = fGain * 1024;

    total = sizeof(analog_gain_table) / sizeof(EI_U32);

    while (i < total) {
        if (Gain < analog_gain_table[i]) {
            break;
        }
        i++;
    }

    tol_dig_gain = (Gain * 1000 / analog_gain_table[i - 1]) * 64 / 1000;
    dgain = (tol_dig_gain << 2) & 0xfffc;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {

        /* set again */
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb4, LinerRegValTable[i - 1][0]);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb3, LinerRegValTable[i - 1][1]);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb8, LinerRegValTable[i - 1][2]);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb9, LinerRegValTable[i - 1][3]);

        /* set dgain */
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb1, (dgain >> 8) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0xb2, (dgain >> 0) & 0xff);
    }
    if (s32Ret != EI_SUCCESS) {
        PRT_VISS_ERR("\n");
    }

    return s32Ret;
}

static EI_S32 CAMERA_InitAeExpFunction(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));

    pstExpFuncs->pfnGetAeDefault    = CAMERA_GetAeDefault;
    pstExpFuncs->pfnSetFps          = CAMERA_SetFps;
    pstExpFuncs->pfnSetExpTime      = CAMERA_SetExpTime;
    pstExpFuncs->pfnSetGain         = CAMERA_SetGain;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAwbDefault(ISP_DEV dev, AWB_SENSOR_DEFAULT_S *pstAwbSnsDft)
{
    CAMERA_CHECK_POINTER(pstAwbSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAwbExpFunction(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
    pstExpFuncs->pfnGetAwbDefault = CAMERA_GetAwbDefault;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_RegisterIspCallback(VISS_DEV Dev, ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;
    AE_SENSOR_REGISTER_S  stAeRegister;
    AWB_SENSOR_REGISTER_S stAwbRegister;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    SNS_SET_ISP_TO_VISS(dev, Dev);

    stAeRegister.SnsId = SNS_ID;
    stAwbRegister.SnsId = SNS_ID;

    s32Ret  = CAMERA_InitAeExpFunction(&stAeRegister.stSnsExp);
    s32Ret |= EI_MI_AE_SensorRegCallBack(dev, pstAeLib, &stAeRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret  = CAMERA_InitAwbExpFunction(&stAwbRegister.stSnsExp);
    s32Ret |= EI_MI_AWB_SensorRegCallBack(dev, pstAwbLib, &stAwbRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterIspCallback(ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    s32Ret = EI_MI_AE_SensorUnRegCallBack(dev, pstAeLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = EI_MI_AWB_SensorUnRegCallBack(dev, pstAwbLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize           = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat    = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate      = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraGc2053mipiObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = CAMERA_RegisterIspCallback,
    .pfnUnRegisterIspCallback   = CAMERA_UnregisterIspCallback,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

